//////////////////////////////////////////////////////////////////////
//
// CryEngine Source code
//
// File:Skeleton.cpp
// Implementation of Skeleton class
//
// History:
// January 12, 2005: Created by Ivo Herzeg <ivo@crytek.de>
//
//////////////////////////////////////////////////////////////////////

#ifndef _SKELETON_POSE_H
#define _SKELETON_POSE_H

#include "Skeleton.h"

#include "ModelAnimationSet.h"
#include "GeomQuery.h"
#include "Memory/Pool.h"

class CCharacterModel;
class CSkinInstance;
class CCharInstance;
class CSkeletonAnim;
class CSkeletonPose;
class CAttachment;
class CLookAt;

struct Locator;
 

#define CA_FADEOUT (0x40000000) 

#define LHEEL (0x01)
#define RHEEL (0x02)
#define LTOE0 (0x04)
#define RTOE0 (0x08)
#define LNUB0 (0x10)
#define RNUB0 (0x20)

struct CPhysicsJoint
{
	CPhysicsJoint() : m_DefaultRelativeQuat(IDENTITY), m_qRelFallPlay(IDENTITY)
	{
		m_qRelPhysParent[0].SetIdentity();
		m_qRelPhysParent[1].SetIdentity();
	}
	void GetMemoryUsage(ICrySizer *pSizer ) const{}	

	QuatT m_DefaultRelativeQuat;		//default relative joint (can be different for every instance)
	Quat m_qRelPhysParent[2];				// default orientation relative to the physicalized parent
	Quat m_qRelFallPlay;
};

struct CCGAJoint
{ 
	CCGAJoint() : m_CGAObjectInstance(0), m_pRNTmpData(0),m_qqqhasPhysics(~0),m_pMaterial(0) {}
	~CCGAJoint() 
	{
		if(m_pRNTmpData)
			GetISystem()->GetI3DEngine()->FreeRNTmpData(&m_pRNTmpData);
		assert(!m_pRNTmpData);
	};
	void GetMemoryUsage(ICrySizer *pSizer ) const{}

	_smart_ptr<IStatObj> m_CGAObjectInstance;	//Static object controlled by this joint (this can be different for every instance).
	struct CRNTmpData * m_pRNTmpData; // pointer to LOD transition state (allocated in 3dngine for visible objects)
	int m_qqqhasPhysics;						//>=0 if have physics (don't make it int16!!)
	_smart_ptr<IMaterial> m_pMaterial; // custom material override
};


struct ColorRGB{ uint8 r,g,b; };


struct SPostProcess
{
	QuatT m_RelativePose;
	uint32 m_JointIdx;

	SPostProcess(){};

	SPostProcess(int idx,const QuatT& qp)
	{
		m_JointIdx=idx;
		m_RelativePose=qp;
	}
	void GetMemoryUsage(ICrySizer *pSizer ) const{}
};


struct aux_bone_info {
	quaternionf quat0;
	Vec3 dir0;
	int iBone;
	f32 rlen0;
};

struct aux_phys_data {
	IPhysicalEntity *pPhysEnt;
	Vec3 *pVtx;
	Vec3 *pSubVtx;
	const char *strName;
	aux_bone_info *pauxBoneInfo;
	int nChars;
	int nBones;
	int iBoneTiedTo[2];
	int nSubVtxAlloc;
	bool bPhysical;
	bool bTied0,bTied1;
	int iBoneStiffnessController;

	void GetMemoryUsage(ICrySizer * pSizer) const {}
};


struct SBatchUpdateValidator : pe_action_batch_parts_update::Validator {
	SBatchUpdateValidator() { 
		bValid=1; nRefCount=1; lock=0; 
		WriteLock glock(g_lockList);
		next=prev=&g_firstValidator; next=g_firstValidator.next; g_firstValidator.next->prev=this; g_firstValidator.next=this; 
	}
	~SBatchUpdateValidator() { WriteLock glock(g_lockList); prev->next=next; next->prev=prev; }
	int bValid;
	int nRefCount;
	volatile int lock;
	volatile SBatchUpdateValidator *next,*prev;
	static SBatchUpdateValidator g_firstValidator;
	static volatile int g_lockList;

	virtual bool Lock() { 
		if (!bValid) { Release(); return false; } 
		CryReadLock(&lock,false); return true; 
	}
	virtual void Unlock() { CryReleaseReadLock(&lock); Release(); }
	int AddRef() { return CryInterlockedIncrement(&nRefCount); }
	void Release() { if (CryInterlockedDecrement(&nRefCount)<=0) delete this; }
};
	


#include "PoseModifier/PoseBlenderAim.h"
#include "PoseModifier/PoseBlenderLook.h"
#include "PoseModifier/FeetLock.h"
#include "PoseModifier/GroundAlignment.h"


//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
class CSkeletonPose: public ISkeletonPose
{
	friend class CSkinInstance;

public:
	CSkeletonPose();
	~CSkeletonPose(); 

	//-----------------------------------------------------------------------------------
	//---- interface functions to access bones ----
	//-----------------------------------------------------------------------------------
	size_t SizeOfThis();
	void GetMemoryUsage(ICrySizer * pSizer) const;

	//! Returns the number of bones; all bone ids are in the range from 0 to this number exclusive; 0th bone is the root
	uint32 GetJointCount() const 
	{ 




		return m_pModelSkeleton->m_poseData.GetJointCount();

	}

	// finds the index by its name; returns the index of the bone
	int16 GetJointIDByName (const char* szJointName) const { return m_pModelSkeleton->GetJointIDByName(szJointName); };
	int16 GetJointIDByCRC32 (uint32 crc) const { return m_pModelSkeleton->GetJointIDByCRC32(crc); };
	// finds the parent-index by the child-index and returns the parent-index
	int16 GetParentIDByID (int32 ChildID) const { return m_pModelSkeleton->GetJointParentIDByID(ChildID); };
	// returns the name of bone from bone table, return zero id nId is out of range
	const char* GetJointNameByID(int32 nId) const { return m_pModelSkeleton->GetJointNameByID(nId); };

	VIRTUAL uint32 GetJointCRC32 (int32 nJointID) const;
	uint32 GetChildrenCount(int32 parentID) const;
	int16 GetChildID(int32 parentID, int32 childIndex) const;

	const QuatT& GetAbsJointByID(int32 id) 
	{ 
		int32 numJoints=(int)CSkeletonPose::GetJointCount();
		if(id>=0 && id<numJoints)
			return GetPoseData().m_pJointsAbsolute[id];
		assert(0);
		return g_IdentityQuatT; 
	}

	void SetAbsJointByID(int32 id, const QuatT& pose)
	{
		Skeleton::CPoseData& poseData = GetPoseDataForceWriteable();

		int32 numJoints=(int)CSkeletonPose::GetJointCount();
		if(id>=0 && id<numJoints)
		{
			poseData.m_pJointsAbsolute[id] = pose;
			if (m_parrModelJoints[id].m_idxParent>=0 && m_parrModelJoints[id].m_idxParent<numJoints)
			{
				poseData.m_pJointsRelative[id].t = (pose.t - poseData.m_pJointsAbsolute[m_parrModelJoints[id].m_idxParent].t) * poseData.m_pJointsAbsolute[m_parrModelJoints[id].m_idxParent].q;
				poseData.m_pJointsRelative[id].q = poseData.m_pJointsAbsolute[m_parrModelJoints[id].m_idxParent].q.GetInverted() * pose.q;
			}

			for (int32 i=1; i<numJoints; i++)
			{
				int32 p=m_parrModelJoints[i].m_idxParent;
				poseData.m_pJointsAbsolute[i]	= poseData.m_pJointsAbsolute[p] * poseData.m_pJointsRelative[i];
			}
		} 
	}
  void SetDefaultAbsInvJointByID(int32 nJointID, const QuatT& pose)
  {
		//sorry, not enough mememory on consoles. Need to do it at runtime
  //  m_parrModelJoints[nJointID].m_DefaultAbsPoseInverse = pose;
  }
	const QuatT& GetRelJointByID(int32 id) 
	{ 
		int32 numJoints=(int)CSkeletonPose::GetJointCount();
		if(id>=0 && id<numJoints)
			return GetPoseData().m_pJointsRelative[id];
		assert(!"GetRelJointByID() - Index out of range!");
		return g_IdentityQuatT;
	}

	const QuatT& GetDefaultAbsJointByID(int32 id) 
	{ 
		const QuatT *ret = &g_IdentityQuatT;
		int32 numJoints=(int)CSkeletonPose::GetJointCount();
		if(id>=0 && id<numJoints)
			ret = &GetPoseDataDefault().m_pJointsAbsolute[id]; 
		else
		{
			assert(!"GetDefaultAbsJointByID() - Index out of range!");
		}

		return *ret;
	}
	const QuatT& GetDefaultRelJointByID(int32 id) 
	{ 
		int32 numJoints=(int)GetPoseDataDefault().GetJointCount();
		if(id>=0 && id<numJoints)
			return m_pModelSkeleton->m_poseData.m_pJointsRelative[id];
		assert(!"GetDefaultRelJointByID() - Index out of range!");
		return g_IdentityQuatT; 
	}

	void InitSkeletonPose( CCharInstance* pInstance, CSkeletonAnim* pSkeletonAnim);
	void InitPhysicsSkeleton();
	void InitCGASkeleton();

	void SetDefaultPosePerInstance(bool bDataPoseForceWriteable);
	void SetDefaultPoseExecute(bool bDataPoseForceWriteable);
	void SetDefaultPose();
	
	//------------------------------------------------------------------------------------	

	void UpdateAttachments(Skeleton::CPoseData& poseData, const QuatT& locationPhysics, const QuatTS& locationAnimation, float fZoomAdjustedDistanceFromCamera, bool onRender);

	void SkeletonPostProcess(Skeleton::CPoseData& poseData, const QuatT &rPhysLocationNext, const QuatTS &rAnimLocationNext, IAttachment* pIAttachment, float fZoomAdjustedDistanceFromCamera, uint32 OnRender=0 );

	SFootPlant BlendFootPlants(const SFootPlant& fp0, const SFootPlant& fp1, f32 t);
	void AdjustFeetHelper( QuatT &rAbsoluteCalf, QuatT &rRelativeCalf, QuatT &rAbsoluteTight, QuatT &rAbsoluteFoot,QuatT &rRelativeFoot, const Vec3 &rCross, const Vec3 &rKneeDir, uint32 iteration, float knee_factor );



	int32 m_nForceSkeletonUpdate;
	void SetForceSkeletonUpdate(int32 i) { m_nForceSkeletonUpdate=i; };

	void UpdateBBox(uint32 update=0);

	//-----------------------------------------------------------------------------------

	// LimbIk
public:
	uint32 SetHumanLimbIK(const Vec3& vWorldPos, const char* strLimb);
	uint32 SetHumanLimbIK(const QuatT& vWorldPos, const char* strLimb, const bool adjustEndEffector = false);
	uint32 SetHumanLimbIK(const QuatT& vWorldPos, uint64 strLimb, const bool adjustEndEffector = false);

	// use only if you cannot wait and need the results right away
	uint32 SetHumanLimbIK_ExecuteImmediately(const QuatT& wgoal, const char* limb, const bool adjustEndEffector = false);
	uint32 SetHumanLimbIK_ExecuteImmediately(const QuatT& wgoal, uint64 limb, const bool adjustEndEffector = false);


	IAnimationPoseModifierPtr m_limbIk;

	// GroundAlignment
public:
	void EnableFootGroundAlignment(bool enable) { m_bGroundAlignment = enable; }
	void SetGroundAlignmentData(const bool bAlignSkeletonVertical, const f32 rootHeight, const Plane& planeLeft, const Plane& planeRight, int32 pelvisIDX);

	IAnimationGroundAlignmentPtr m_groundAlignment;
	bool m_bGroundAlignment;
	bool m_bGroundAlign;

	IAnimationGroundAlignment* GetGroundAlignment() { return m_groundAlignment.get(); }

	// LookIk
public:
	IAnimationPoseBlenderDirPtr m_PoseBlenderLook;
	IAnimationPoseBlenderDir* GetIPoseBlenderLook() { return m_PoseBlenderLook.get(); }
	CPoseBlenderLook& GetPoseBlenderLook();// { return *static_cast<CPoseBlenderLook*>(m_PoseBlenderLook.get()); }

	void SetLookIK(uint32 ik, f32 FOR, const Vec3& LookAtTarget,const f32 *customBlends, bool allowAdditionalTransforms, bool ignoreAimBlend);
	uint8 IsLookIKEnabled();
	IAnimationPoseModifierPtr m_LookAt;
	CLookAt& m_LookIK() { return *reinterpret_cast<CLookAt*>(m_LookAt.get()); }
	void SetPoseBlenderLookLayer(uint32 layer);


	IAnimationPoseBlenderDirPtr m_PoseBlenderAim;
	IAnimationPoseBlenderDir* GetIPoseBlenderAim() { return m_PoseBlenderAim.get(); }
	CPoseBlenderAim& GetPoseBlenderAim();
	void SetAimIK(bool bUseAimIK, const Vec3& AimAtTarget, float blendTime = -1.0f ); 
	void SetAimIKFadeAngle(f32 angle) { GetPoseBlenderAim().SetFadeoutAngle(angle); }
	void SetAimIKFadeOutTime(f32 time) { GetPoseBlenderAim().SetFadeOutTime(time); }
	void SetAimIKFadeInTime(f32 time) { GetPoseBlenderAim().SetFadeInTime(time); }
	void SetAimIKTargetSmoothTime(f32 fSmoothTime) { GetPoseBlenderAim().SetTargetSmoothTime(fSmoothTime); }
	void SetAimIKPolarCoordinates(const Vec2& pc) { GetPoseBlenderAim().SetPolarCoordinates(pc); }
	uint32 GetAimIKStatus() { return GetPoseBlenderAim().GetStatus(); }
	f32 GetAimIKBlend() { return GetPoseBlenderAim().GetBlend(); }

	void SetPoseBlenderAimState(bool bEnable);
	void SetPoseBlenderAimLayer(uint32 layer);

	// Recoil
public:
	void ApplyRecoilAnimation(f32 fDuration, f32 fImpact, f32 fKickIn, uint32 arms=3);

	IAnimationPoseModifierPtr m_recoil;

	// FeetLock
public:
	CFeetLock m_feetLock;

public:

	//------------------------------------------------------------------------
	//----> Foot Anchoring
	//------------------------------------------------------------------------
	void SetFootAnchoring(uint32 at){ };
	
	//void SetFootAnchoring(uint32 at){ m_FootAnchor.m_UseFootAnchoring=at > 0; };
	void FootAnchoring( const SFootPlant& BFPlant, uint8 Foot, const QuatTS& rAnimLocationCurr );
	//void AbsoluteLegPosition(const QuatTS& rAnimLocationCurr);
	//void EaseOut_LAnkle();
	//void EaseOut_RAnkle();
	//SFootAnchor m_FootAnchor;

	//------------------------------------------------------------------------
	//----> human limb-IK
	//------------------------------------------------------------------------
	uint32 SetCustomArmIK(const Vec3& goal,int32 idx0,int32 idx1,int32 idx2) { return -1; }






	void SetPostProcessQuat(int32 idx, const QuatT& qt )
	{
		if (idx >= 0)
			m_arrPostProcess.push_back( SPostProcess(idx,qt) );
	}
	DynArray<SPostProcess> m_arrPostProcess;


	int (*m_pPostProcessCallback)(ICharacterInstance*,void*);
	void* m_pPostProcessCallbackData;
	void SetPostProcessCallback(CallBackFuncType func, void *pdata)
	{
		m_pPostProcessCallback = func;
		m_pPostProcessCallbackData = pdata;
	}

	void* GetPostProcessCallback(void* &pdata)
	{
		pdata = m_pPostProcessCallbackData;
		return (void*)m_pPostProcessCallback;
	}



	//-------------------------------------------------------------------------------
	//---         Physics from CSkinInstance                                  ---
	//-------------------------------------------------------------------------------
	IStatObj* GetStatObjOnJoint(int32 nId);
	void SetStatObjOnJoint(int32 nId, IStatObj* pStatObj);
	IPhysicalEntity *GetPhysEntOnJoint(int32 nId) { return m_ppBonePhysics ? m_ppBonePhysics[nId]:0; }
	void SetPhysEntOnJoint(int32 nId, IPhysicalEntity *pPhysEnt);
	int GetPhysIdOnJoint(int32 nId);
	void SetMaterialOnJoint(int32 nId, IMaterial* pMaterial) { assert(nId>=0 && nId<(int32)m_arrCGAJoints.size()); m_arrCGAJoints[nId].m_pMaterial = pMaterial; }
	IMaterial* GetMaterialOnJoint(int32 nId) { assert(nId>=0 && nId<(int32)m_arrCGAJoints.size()); return m_arrCGAJoints[nId].m_pMaterial; }

	void SetRagdollDefaultPose() { m_bSetRagdollDefaultPoseRequested=1; }
	void DoSetRagdollDefaultPose(Skeleton::CPoseData& poseData);
	int getBonePhysChildIndex (int nBoneIndex, int nLod=0);
	int getBonePhysParentIndex (int nBoneIndex, int nLod=0); // same, but finds the first ancestor that has physical geometry
	int getBonePhysParentOrSelfIndex (int nBoneIndex, int nLod=0);
	int GetBoneSurfaceTypeId(int nBoneIndex, int nLod=0);

	int TranslatePartIdToDeadBody(int partid);

	bool SetFnPAnimGroup(const char *name);
	bool SetFnPAnimGroup(int idx);

	void BuildPhysicalEntity(IPhysicalEntity *pent,f32 mass,int surface_idx,f32 stiffness_scale, int nLod=0,int partid0=0, 
		const Matrix34 &mtxloc=Matrix34(QuatT(IDENTITY)));
	IPhysicalEntity *GetCharacterPhysics(const char *pRootBoneName);
	IPhysicalEntity *GetCharacterPhysics(int iAuxPhys);
	int GetAuxPhysicsBoneId(int iAuxPhys, int iBone=0) { 
		PREFAST_SUPPRESS_WARNING(6385) 
		return (iAuxPhys<m_nAuxPhys && iBone<m_auxPhys[iAuxPhys].nBones) ? m_auxPhys[iAuxPhys].pauxBoneInfo[iBone].iBone : -1;
	}
	void DestroyCharacterPhysics(int iMode=0);
	IPhysicalEntity* CreateCharacterPhysics(IPhysicalEntity *pHost, f32 mass,int surface_idx,f32 stiffness_scale, int nLod=0, 
		const Matrix34 &mtxloc=Matrix34(QuatT(IDENTITY)));
	int CreateAuxilaryPhysics(IPhysicalEntity *pHost, const Matrix34 &mtx, int nLod=0);
	int CreateAuxilaryPhysics(IPhysicalEntity *pHost, const Matrix34 &mtx, f32 scale,Vec3 offset, int nLod);
	int FillRopeLenArray(float *arr,int i0,int sz);

	IPhysicalEntity *RelinquishCharacterPhysics(const Matrix34 &mtx, float stiffness=0.0f, bool bCopyJointVelocities=false, const Vec3 &velHost=Vec3(ZERO));
	bool AddImpact(int partid, Vec3 point,Vec3 impact);
	void ResetNonphysicalBoneRotations(Skeleton::CPoseData& poseData, int nLOD, f32 fBlend);
	void UnconvertBoneGlobalFromRelativeForm(Skeleton::CPoseData& poseData, bool bNonphysicalOnly, int nLod=0, bool bRopeTipsOnly=false);
	//! marks all LODs as needed to be reskinned
	void ForceReskin ();

	IPhysicalEntity* GetCharacterPhysics() const { return m_pCharPhysics; }
	void SetCharacterPhysics(IPhysicalEntity *pent) { 
		m_pCharPhysics=pent; m_bAliveRagdoll = 0;	m_timeStandingUp = -1;
	}

	void DestroyPhysics();
	void SetAuxParams(pe_params* pf);

	void SetOffset(Vec3 offset) {	m_vOffset = offset; }
	Vec3 GetOffset() { return m_vOffset; }

	CModelJoint* GetModelJointPointer(int nBone) { return &m_parrModelJoints[nBone]; }
	//returns the j-th child of i-th child of the given bone
	int GetModelJointChildIndex (int nBone, int i)
	{
		assert (i >= 0 && i<(int)GetModelJointPointer(nBone)->numChildren());
		return nBone + GetModelJointPointer(nBone)->getFirstChildIndexOffset() + i;
	}
	// given the bone index, (INDEX, NOT ID), returns this bone's parent index
	uint32 getBoneParentIndex (uint32 nBoneIndex);
		
	
	void SetFootPlants(int val) { m_FootPlants = (val > 0); };
	int GetFootPlants() const { return m_FootPlants; };

	int GetInstanceVisible() const { return m_bFullSkeletonUpdate; };

	//just for debugging
	void DrawPose(const Skeleton::CPoseData& pose, QuatT transformation);
	void DrawBBox( const Matrix34& rRenderMat34 );
	void DrawSkeleton( const Matrix34& rRenderMat34, uint32 shift=0 );
	void DrawArrow( const QuatT& location, const Vec3& vTravelDir,f32 length, ColorB col );
	void DrawArrowArc( const QuatT& location, const f32 turnAngle, const f32 length, const f32 slope, const ColorB& col );
	void DrawLocator(const QuatTS &rAnimLocationNext, const int cvarValue = 1);
	void DrawPositionPost(const QuatT& rPhysLocationNext, const QuatTS &rAnimLocationNext);
	void DrawDebugCaps();
	f32 SecurityCheck();
	uint32 IsSkeletonValid();
	int32 m_Superimposed;
	void SetSuperimposed(uint32 i){ m_Superimposed=i; };
	void DrawThinSkeletons( const QuatT& m34, const std::vector< std::vector<DebugJoint> >& arrSkeletons, int32 nAnimID,int32 nGlobalAnimID );
	void DrawThinSkeleton( const QuatT& m34, const std::vector<DebugJoint>& arrSkeleton, uint8 FootPlant, ColorB col );
	const AABB& GetAABB() const { return m_AABB; }
	void ExportSkeleton();

	// Physics
public:
	void SynchronizeWithPhysicalEntity(IPhysicalEntity *pent,const Vec3& posMaster,const Quat& qMaster);

	void SynchronizeWithPhysicsPrepare(Memory::CPool& memoryPool, const QuatT& locationPhysics, const QuatTS& locationAnimation);
	void SynchronizeWithPhysics(Skeleton::CPoseData& poseData, const QuatT& locationPhysics, const QuatTS& locationAnimation, const QuatT& attachmentParent=QuatT(IDENTITY));
	void SynchronizeWithPhysicsPost(const QuatT& locationPhysics, const QuatTS& locationAnimation);

	void SPU_SynchronizeWithPhysics(Skeleton::CPoseData& poseData, const QuatT& locationPhysics, const QuatTS& locationAnimation);

private:
	void InitializeAnimToPhysIndexArray();

	void ProcessPhysicsImpact(Skeleton::CPoseData& poseData, float fDeltaTimePhys, int nNeff);
	void ProcessPhysicsFallAndPlay(Skeleton::CPoseData& poseData, float fDeltaTimePhys);

	void ProcessPhysics(Skeleton::CPoseData& poseData, const QuatT& rPhysEntityLocation, f32 fDeltaTimePhys, int nNeff, SCharUpdateFeedback *pCharFeedback=0, const QuatT& attachmentParent=QuatT(IDENTITY));

	void SynchronizeWithPhysicalEntity(Skeleton::CPoseData& poseData, IPhysicalEntity *pent, const Vec3& posMaster,const Quat& qMaster, QuatT offset, int iDir=-1 );

	// chooses dead lod, if we have one
	int GetPhysicsLod() const { return m_bHasPhysicsProxies ? 1 : 0; }

public:
	struct PhysData
	{
		QuatT location;
		Quat rotation;
		Ang3 angles;

		bool bSet : 1;
		bool bSet2 : 1;
	} * m_pPhysBuffer;
	bool m_bPhysicsSynchronize;
	bool m_bPhysicsSynchronizeFromEntity;
	bool m_bPhysBufferFilled;
	pe_type m_ePhysicsEntityType;

	struct PhysAuxData
	{
		Matrix34 matrix;
		Vec3* pPoints;

		bool bSet : 1;
		bool bPosHostPivot : 1;
	} * m_pPhysAuxBuffer;
	bool m_bPhysicsSynchronizeAux;

private:
	void SPU_Physics_SynchronizeFromEntityPrepare(Memory::CPool& memoryPool, IPhysicalEntity* pent);
	void SPU_Physics_SynchronizeFromEntity(Skeleton::CPoseData& poseData, IPhysicalEntity* pent, const Vec3& posMaster, const Quat& qMaster, QuatT offset);
	void SPU_Physics_SynchronizeFromEntityArticulated(Skeleton::CPoseData& poseData, float fDeltaTimePhys, int nNeff);
	void SPU_Physics_SynchronizeFromAuxPrepare(Memory::CPool& memoryPool, int nNeff);
	void SPU_Physics_SynchronizeFromAux(Skeleton::CPoseData& poseData, const Matrix34& locationPhysics);
	void SPU_Physics_SynchronizeFrom(Skeleton::CPoseData& poseData, const QuatT& rPhysEntityLocation, f32 fDeltaTimePhys, int nNeff, SCharUpdateFeedback *pCharFeedback=0);

	void SPU_SynchronizeWithPhysicsPrepare(Memory::CPool& memoryPool);

	void Physics_SynchronizeToEntity(IPhysicalEntity& physicalEntity, QuatT offset);
	void Physics_SynchronizeToEntityArticulated(float fDeltaTimePhys, int nNeff);
	void Physics_SynchronizeToAux(const Skeleton::CPoseData& poseData, const QuatT& locationPhysics, int nNeff, const QuatT& attachmentParent=QuatT(IDENTITY));

	// FallAndPlay
public:
	void FindSpineBones();

	void Fall();
	void GoLimp();
	void StandUp(const Matrix34 &mtx, bool b3DOF, IPhysicalEntity *&pNewPhysicalEntity, Matrix34 &mtxDelta);

	float Falling() const;
	float Lying() const;
	float StandingUp() const
	{
		return m_timeStandingUp;
	}

	int GetFallingDir();

public:
	IPhysicalEntity *m_pCharPhysics;
	IPhysicalEntity *m_pPrevCharHost;
	IPhysicalEntity **m_ppBonePhysics;

public:
	CCharInstance* m_pInstance;
	CModelSkeleton* m_pModelSkeleton;

	CModelJoint* m_parrModelJoints;

public:
	ILINE const Skeleton::CPoseData& GetPoseData() const { return m_poseData; }
	ILINE Skeleton::CPoseData& GetPoseDataExplicitWriteable() { return m_poseData; }
	Skeleton::CPoseData& GetPoseDataForceWriteable();
	Skeleton::CPoseData* GetPoseDataWriteable();
	ILINE const Skeleton::CPoseData& GetPoseDataDefault() const { return *m_pPoseDataDefault; }


	bool PreparePoseDataAndLocatorWriteables(Memory::CPool& memoryPool);
	void SynchronizePoseDataAndLocatorWriteables();

private:
	Skeleton::CPoseData m_poseData;
	Skeleton::CPoseData m_poseDataWriteable;
	Skeleton::CPoseData* m_pPoseDataWriteable;
	Skeleton::CPoseData* m_pPoseDataDefault;

public:
	DynArray<Vec3>		    m_FaceAnimPosSmooth; 
	DynArray<Vec3>		    m_FaceAnimPosSmoothRate; 
	DynArray<CCGAJoint>     m_arrCGAJoints;
	DynArray<CPhysicsJoint> m_arrPhysicsJoints;
	CGeomExtents					m_Extents;
  //Pavlo: this array is used only for character editor

	AABB m_AABB;

	Vec3 m_vOffset;
	int m_iSpineBone[3];
	mutable uint32 m_nSpineBones;
	int m_nAuxPhys;
	int m_iSurfaceIdx;
	int m_iFlyDir;
	aux_phys_data m_auxPhys[12];
	int m_b3DOFStandup;
	f32 m_fPhysBlendTime,m_fPhysBlendMaxTime,m_frPhysBlendMaxTime;
	float m_stiffnessScale;
	float m_timeRagdolled,m_timeLying,m_timeNoColl,m_timeStandingUp;
	int m_iFnPSet;
	f32 m_fScale;
	f32 m_fMass;
	Vec3 m_prevPosPivot,m_velPivot;
	DynArray<QuatT> m_physJoints;
	DynArray<int> m_physJointsIdx;
	int m_nPhysJoints;
	SBatchUpdateValidator *m_pPhysUpdateValidator;

	uint32 m_LookIKLayer;
	uint16 m_lastPushedLookPose;

	bool m_bInstanceVisible : 1;
	bool m_bFullSkeletonUpdate : 1;
	uint32 m_bAllNodesValid : 1; //True if this animation was already played once.
	bool m_bPhysicsRelinquished : 1;
	bool m_FootPlants : 1;
	bool m_bHasPhysics : 1;
	bool m_bHasPhysicsProxies : 1;
	bool m_bPhysicsAwake : 1;
	bool m_bPhysicsWasAwake : 1;
	bool m_bAliveRagdoll : 1;
	bool m_bLimpRagdoll : 1;
	bool m_bSetRagdollDefaultPoseRequested : 1;
	bool m_bSetDefaultPoseExecute : 1;

	CSkeletonAnim* m_pSkeletonAnim;
}_ALIGN(128);

#endif // _SKELETON_POSE_H
